; haribote-os boot asm
; TAB=4

BOTPAK	EQU		0x00280000		; bootpack.c的装载地址
DSKCAC	EQU		0x00100000		; ƒfƒBƒXƒNƒLƒƒƒbƒVƒ…‚ÌêŠ
DSKCAC0	EQU		0x00008000		; ƒfƒBƒXƒNƒLƒƒƒbƒVƒ…‚ÌêŠiƒŠƒAƒ‹ƒ‚[ƒhj

; BOOT_INFO
CYLS	EQU		0x0ff0			; 设定启动区
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 颜色位数
SCRNX	EQU		0x0ff4			; 分辨率x
SCRNY	EQU		0x0ff6			; 分辨率y
VRAM	EQU		0x0ff8			; 显存起始地址 (把地址存在0x0ff8这个地方 ，实际上地址是0xa0000)

		ORG		0xc200			; 程序装载的地址

; 显卡参数设置
		MOV BX,0x4105  ;VAE模式 ，1024*768
		MOV AX,0x4f02
		;MOV		AL,0x13			; VGA显卡 320x200x8位色彩
		;MOV		AH,0x00
		INT		0x10            ;显卡调用
		MOV		BYTE [VMODE],8	; 记录画面模式
		MOV		WORD [SCRNX],1024
		MOV		WORD [SCRNY],768
		MOV		DWORD [VRAM],0xe0000000
		;MOV		DWORD [VRAM],0x000a0000   ;这种画面模式下VRAM 显存从0xa0000 - 0xaffff ，共64KB

; 从BIOS取得键盘各种LED指示灯状态

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

; PIC关闭一切中断
;	如果要初始化PIC ，需要在CLI前进行 ，否则可能会被挂起
;	随后进行PIC初始化
;	相当于 io_out8(PIC0_IMR,0xff) ;  io_out8(PIC1_IMR,0xff) ;  

		MOV		AL,0xff
		OUT		0x21,AL
		NOP						; 部分机器不能连续执行out指令
		OUT		0xa1,AL

		CLI						; 禁止CPU级别中断int0 - int1f

; 让CPU能访问1M以上的空间 （设定A20GATE ON ）  
;因为最初电脑只有1M ,为了兼容旧操作系统，让1M以后的内存需要手动开启 

		CALL	waitkbdout     ;wait_KBC_SEND_ready () ;
		MOV		AL,0xd1
		OUT		0x64,AL        ;io_out8(PORT_KEYCMD ,KEYCMD_WRITE_OUTPORT); 
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL        ;io_out8(PORT_KEYDAT ,KBC_OUTPORT_A20G_ENABLE); 
		CALL	waitkbdout


; 切换到保护模式： 
[INSTRSET "i486p"]				; 为了能够使用386以后的指令 ，如LGDT、EAX ,CR0等

		LGDT	[GDTR0]			; 随意设定一个GDT地址
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	; bit31(第三十二位)‚设置为0
		OR		EAX,0x00000001	; bit0(第一位) 设置为1
		MOV		CR0,EAX        ;这样就进入了保护模式
		JMP		pipelineflush
pipelineflush:
		MOV		AX,1*8			; 可读写的段 32bit
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX

; bootpack代码的转送

		MOV		ESI,bootpack	; 源  
		MOV		EDI,BOTPAK		; 目的  0x00280000
		MOV		ECX,512*1024/4  ; 大小512KB  ，因为单位是双字DD
		CALL	memcpy

;

;转送启动区IPL

		MOV		ESI,0x7c00		; 源
		MOV		EDI,DSKCAC		; 目的0x00010000
		MOV		ECX,512/4       ; 512B
		CALL	memcpy

; 剩下的其他代码

		MOV		ESI,DSKCAC0+512	; 源0x00008000 + 512  （0x8200）
		MOV		EDI,DSKCAC+512	; 目的0x00010000  +512
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	ECX,512*18*2/4	; 柱面数 x 内存大小/每柱面
		SUB		ECX,512/4		; 减去IPL的512B大小
		CALL	memcpy

; 以上必须由 asmhead.nas完成 ，至此全部完毕
;	以后的工作由bootpack完成

; bootpack的启动

		MOV		EBX,BOTPAK
		MOV		ECX,[EBX+16]
		ADD		ECX,3			; ECX += 3;
		SHR		ECX,2			; ECX /= 4;
		JZ		skip			; 没有要转送的东西时
		MOV		ESI,[EBX+20]	; 
		ADD		ESI,EBX
		MOV		EDI,[EBX+12]	; 
		CALL	memcpy
skip:
		MOV		ESP,[EBX+12]	; ƒXƒ^ƒbƒN‰Šú’l
		JMP		DWORD 2*8:0x0000001b

waitkbdout:
		IN		 AL,0x64
		AND		 AL,0x02
		JNZ		waitkbdout		; AND‚ÌŒ‹‰Ê‚ª0‚Å‚È‚¯‚ê‚Îwaitkbdout‚Ö
		RET

memcpy:
		MOV		EAX,[ESI]
		ADD		ESI,4
		MOV		[EDI],EAX
		ADD		EDI,4
		SUB		ECX,1
		JNZ		memcpy			; ˆø‚«ŽZ‚µ‚½Œ‹‰Ê‚ª0‚Å‚È‚¯‚ê‚Îmemcpy‚Ö
		RET
; memcpy‚ÍƒAƒhƒŒƒXƒTƒCƒYƒvƒŠƒtƒBƒNƒX‚ð“ü‚ê–Y‚ê‚È‚¯‚ê‚ÎAƒXƒgƒŠƒ“ƒO–½—ß‚Å‚à‘‚¯‚é

		ALIGNB	16
GDT0:
		RESB	8				; ƒkƒ‹ƒZƒŒƒNƒ^
		DW		0xffff,0x0000,0x9200,0x00cf	; “Ç‚Ý‘‚«‰Â”\ƒZƒOƒƒ“ƒg32bit
		DW		0xffff,0x0000,0x9a28,0x0047	; ŽÀs‰Â”\ƒZƒOƒƒ“ƒg32bitibootpack—pj

		DW		0
GDTR0:
		DW		8*3-1
		DD		GDT0

		ALIGNB	16
bootpack:
